'''

'''

print 'LOADING MODULE: BASE'

import inspect, copy, itertools, os, types
from notify.signal import Signal as PySignal
from abc import ABCMeta, abstractmethod
from durus.persistent_dict import PersistentDict
from durus.persistent_list import PersistentList

NewSignal = PySignal()

class StaticData(object):
    
    def __init__(self, default):
        self.default = default
        self.name = None
        
    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        return instance._get_static_data(self.name)

    def __set__(self, instance, value):
        instance._set_static_data(self.name, value)

class Signal(PySignal):
    ''' Defines a Signal, which other functions can hook into to.
        Send a Signal by calling an instance of this class.
        sig = Signal("My Signal")
        sig(1,2,3) # Send a signal with 1, 2, 3 as argument
        cmds.signal("My Signal")(1,2,3) # Same as above
    '''
    _signals = {}
    
    def __init__(self, name="No name"):
        PySignal.__init__(self)
        self.name = name
        self.store()
        NewSignal(self)
        
    def store(self):
        self.__class__._signals[self.name] = self
        
    @classmethod
    def get(cls, name):
        return self._signals.get(name)
        
# Standard Signals
NewComponentType = Signal("New Component Type")
NewComponentInst = Signal("New Component Instance")
NewNamedComponent= Signal("New Named Component")
NewWidgetType    = Signal("New Widget Type")
ComponentSelected= Signal("Component Selected")
ViewSelected     = Signal("View Selected")
NewActionType    = Signal("New Action Type")
NewAttributeType = Signal("New Attribute Type")
ObjectSelected   = Signal("Object Selected")
ComponentUpdated = Signal("Component Updated")
ParentChanged    = Signal("Parent Changed")
ComponentRenamed = Signal("Component Renamed")
NameAboutToChange= Signal("Name About To Change")

class Plugin(object):
    
    def __init__(self, filepath):
        self.server_id = None
        self.revision_id = None
        self.name = None
        self.filepath = filepath
        self.doc = ""
        self.cached_code = None
        self.auto_reload = True
 
    def __str__(self): return "<Plugin " + str(self.name) + ">"
 
    def code(self):
        if not self.cached_code is None:
            return self.cached_code
        code = ""
        with open(self.filepath) as f:
            code = f.read()
        return code    
        
    def set_code(self, code):
        assert isinstance(code, str)
        self.cached_code = code
        if self.filepath is not None:
            with open(self.filepath, 'w') as f:
                f.write(code)
        #if self.auto_reload:
        #    self.load()
 
    def insert_server_info(self):
        pass
 
    def fetch_server_info(self):
        with open(self.filepath) as f:
            pass
  
    def default_name(self):
        return ""
        base = os.path.basename(self.filepath)
        return base.split(".")[0]
  
    



class Expression(str):
    ''' A String that can evaluate itself '''
    def eval(self, instance):
        ''' Evaluate this string.
            The execution as a function that has access to everything in the cmds module.
        '''
        import core.cmds
        core.cmds.reload()
        local = core.cmds.__dict__
        local['self'] = instance
        container = {}
        code = "def exp(): return " + self
        try:
            exec(code, local, container)
            return container.get('exp')()
        except Exception, e:
            print 'Expression Error:', str(e)

class DataContainer(dict):
    ''' A dictionary for storing objects that has be serialized.
        @note: Should only be allowed to container pickle-able objects, maybe only Data objects
    '''


class AttributeMeta(type):
    ''' Meta class for Attributes. 
        Mostly used to register new Attribute-classes in the Scene. '''
    def __new__(self, name, bases, namespace):
        cls = type.__new__(self, name, bases, namespace)
        for name, value in namespace.items():
            if isinstance(value, (StaticData,)):
                value.name = name
        NewAttributeType(cls)
        return cls

class AttributeBase(object):
    ''' The Abstract interface for an Attribute.
        An attribute is a object that gives any kind of data boundaries.
        It's a template for data, and generally serves two purposes:
        1. Validation of data. 
            A Path-Attribute might must be a string that points to an path on the filesystem.
        2. Control get/set of data.
            A Function-Attribute might take a string on set, but return a function on get.
            my_comp.my_func = "print hello"
            my_comp.my_func() # prints hello
            
        A Component class will have a list of Attributes, 
        which defines the data that instances of the component can hold.
    
        An Attribute must also return a DataHandle.
    '''
    
    default = None
    __metaclass__ = AttributeMeta
    
    def __get__(self, instance, owner=None):
        ''' Called when a component instance tries to access this object '''
        
    def __set__(self, instance, value):
        ''' Called when a component instance tries to set the value of this object '''
        
    def can_set(self, value):
        ''' Return True/False whether the given value is allowed to be stored for this Attribute '''
        return True
    
    def can_depend_on(self, attr):
        return issubclass(type(attr), type(self))
    
    def copy(self):
        c = self.__class__()
        c.name = self.name
        for name, value in self.static():
            setattr(c, name, getattr(self, name))
        return c



class DataHandle(object):
    def __init__(self, component, attr):
        self.component = component
        self.attr = attr
        self.change = PySignal()
        
        
    def expression(self):
        return self.attr.get_expression(self.component)
        
    def is_expression(self):
        try:
            return self.attr.is_expression(self.component)
        except Exception, e:
            print 'in is_expression', str(e)
            return False
    
    def new_child(self):
        print 'ADDING CHILD'
        if not self.has_children():
            return
        poly_data = self.get()
        print poly_data
        attr = poly_data.add()
        
    add = new_child
        
    def remove(self):
        self.component.remove(self.attr)
    
    def has_parent(self):
        return self.attr.has_parent(self.component)
    
    def has_children(self):
        return self.attr.has_children(self.component)
        
    def stored_data(self):
        return self.component._get_data(self.attr)
        
    def get(self):
        return getattr(self.component, self.attr.name)
    
    def set(self, value):
        setattr(self.component, self.attr.name, value)


class Link(object):
    ''' Represents a Link between two objects '''
    
class ReferenceLink(Link):
    ''' Represents a Link from a attribute to a Component '''
    def __init__(self, referent, reference):
        self.referent = referent
        self.reference = reference
        self.referent._add_reference_link(self)
        

class LinkIter(object):
    pass
    
class ParentLinkIter(LinkIter):
    ''' Iter to find the Parent of a given component and type.
        @bug: This could possibly go into a infinte loop, if there's a cycle of references
        @note: Maybe use networkx for handling links
    '''

    def __init__(self, component):
        assert isinstance(component, ComponentBase)
        self.component = component
    
    def __getattr__(self, name):
        # Hack
        if name == '__iter__': raise AttributeError()
        if self.component is None: return None
        parents = [link.parent.instance for link in self.component.parents_of_type(name)]
        if not parents:
            for parent in self.component.parent_components():
                piter = ParentLinkIter(parent)
                return getattr(piter, name)
        return parents

class DataIter(object):
    def __init__(self, data, start=0):
        self.data = data
        self.index = start
        
    def __iter__(self): return self
        
    def next(self):
        attr = self.data.attr_at(self.index)
        if attr is None:
            raise StopIterations()
        self.index += 1
        return getattr(self.data, attr.name)
        
class ComponentMeta(type):
    ''' Is responsible for constructing a Component Class.
        It sends out a signal to notify the rest of the application, that a new component has been defined.
        It also constructs a dictionary of the dependencies between the attributes.
    '''

    
    def __new__(self, name, bases, ns):
        cls = type.__new__(self, name, bases, ns)
        cls._attributes = []
        for base in bases:
            if not hasattr(base, '_attributes'):
                continue
            for attr in base._attributes:
                cls._attributes.append(attr)
                
        items = ns.items()
        cls.order = []
        if ns.has_key("__order__"):
            cls.order = ns.get('__order__')
        if not globals().has_key('ComponentBase'):
            return cls
        
        for name, value in ns.items():
            if isinstance(value, (AttributeBase,)):
                value.name = name
                cls._attributes.append(value)
        cls._attributes.sort(cmp=cls.attr_sort )
        
        cls.change = PySignal()
        
        if not ns.has_key('dependencies'):
            cls.dependencies = {}
        for name, attr in ns.items():
            if not isinstance(attr, (AttributeBase,)):
                continue
            attr.name = name
            for dependency in attr.depends:
                if not cls.dependencies.has_key(dependency):
                    cls.dependencies[dependency] = []
                cls.dependencies[dependency].append(attr)
        
        NewComponentType(cls)
        
        return cls
    
    def attr_sort(self, attr1, attr2):
        if not attr1 in self.order and attr2 in self.order:
            return 1
        if attr1 in self.order and not attr2 in self.order:
            return -1
        if not attr1 in self.order and not attr2 in self.order:
            return 0
        
        id1 = self.order.index(attr1)
        id2 = self.order.index(attr2)
        return cmp(id1, id2)
    
    def __repr__(self): return self.__name__ + " (Type)"
    
    

class ComponentBase(object):
    ''' The base class for all components '''
    __metaclass__ = ComponentMeta
    _name = None
    default = None
    dependencies = {}
    plugin = None

    def __new__(self, **kw):
        ''' '''
        inst = object.__new__(self)
        self._dynamic_attrs = []
        inst.__proxy = kw.get('__proxy')
        assert inst.__proxy is None or isinstance(inst.__proxy, ComponentBase)
        
        return inst
    
    def __init__(self, **kw):
        print 'INIT COMPONENT'
        
        self._name = None
        self._data = PersistentDict()
        self._children = PersistentList()
        self._custom_data = PersistentDict()
        self._parent = None
        self._reference_links = []
        
        if kw.get('__register', True):
            NewComponentInst(self, kw.get('override', False))
        
        self.setup(**kw)
        
    def setup(self, **kw):
        
        for name, data in self.static():
            setattr(self, name, kw.get(name, data.default))
        
        
        for attr in self.attrs():
            if isinstance(attr, AttributeBase):
                setattr(self, attr.name, kw.get(attr.name, attr.default_value(self)))
            elif isinstance(attr, ComponentBase):
                raise ValueError("Components as attributes are not allowed anymore")
                #c = copy.deepcopy(attr)
                #setattr(self, attr.name, c)
                #self._set_data(attr, c)
                c = attr.copy()
                self._set_data(attr, c)
                if kw.has_key(attr.name):
                    setattr(self, attr.name, kw.get(attr.name, attr.default))
            
        self.parent = kw.get('parent')
        self.change = PySignal()
        self.name = kw.get("name", self.__class__.__name__)
        
        self.init()
        # Send a signal to tell that a new component instance has been created.
    
    #def __getnewargs__(self): return tuple()
    
    def get_name(self):
        return self._name
    def set_name(self, name):
        NameAboutToChange(self, self.name, name)
    name = property(get_name, set_name)
    
    def get_children(self):
        return self._children
    children = property(get_children)
    
    def _add_reference_link(self, link):
        assert isinstance(link, ReferenceLink)
        self._reference_links.append(link)
    
    def referenced_by(self, type_name):
        result = []
        for ref in self._reference_links:
            if ref.reference.__class__.__name__ == type_name:
                result.append(ref.reference)
        return result
    
    def __getstate__(self):
        data = {'_data':self._data, '_name':self.name, 'default':self.default}#,
                #'depends':self.depends}
        
        data['_parent'] = self.parent
        
        for name, value in self.static():
            data[name] = getattr(self, name)
            
        data['__custom_data__'] = self._custom_data
        #print 'SAVING', data, data['_data'].items()
        return data
    
    def __setstate__(self, state):
        #print 'LOADING', state, state['_data'].items()
        
        #for name, value in state.items():
        #    setattr(self, name, value)
        #    self.__dict__[name] = value
        #self.name = state.get('name')
        for name, value in state.items():
            self.__dict__[name] = value
        
        self._parent = state.get('_parent')
        self._children = []
        self._name = state.get('_name')
        
        self.setup()
        self.init()
        self._custom_data = state.get('__custom_data__', PersistentDict())
        self.__load__(state.get('__custom_data__', {}))
        
    
    def init(self): pass
    
         
    def __save__(self): return {}
    def __load__(self, data): pass 
         
    @classmethod
    def on_reload(cls): pass
         
    @classmethod
    def remove_all_attrs(cls):
        attrs = cls._attributes[:]
        for attr in attrs:
            cls.del_attr(attr)
         
    @classmethod
    def replace_with(cls, new_cls):
        cls.remove_all_attrs()
        for attr in new_cls.class_attrs():
            cls.add_class_attr(attr)
            
        cls.__bases__ = new_cls.__bases__
        cls.dependencies = new_cls.dependencies
        cls.plugin = new_cls.plugin
        
        # Remove methods that exists on cls but not on new_cls
        # and add methods that exists on new_cls but not on cls
        
        cls_methods = []
        cls_vars = []
        for name, value in cls.__dict__.items():
            if name.startswith("_"):
                continue
            if inspect.isfunction(value):
                cls_methods.append(name)
            elif not isinstance(value, AttributeBase):
                cls_vars.append(name)
        
        globals()[cls.__name__] = cls    
        for name in cls_methods:# + cls_vars:
            exec "del "+cls.__name__ + "." + name
        del cls_methods[:]
        
        for name, value in new_cls.__dict__.items():  
            if name.startswith("_") or not inspect.isfunction(value):
                continue
            setattr(cls, name, value)
        
        #cls.on_reload()
        
        cls.change()
         
         
    def __str__(self): return str(self.name) + " ("+ self.__class__.__name__ +")"
         
    def can_depend_on(self, attr):
        return type(self) == type(attr)
        
    def handle(self, attr):
        return DataHandle(self, attr)
    
    def static(self):
        for name, value in inspect.getmembers(self.__class__):
            if isinstance(value, StaticData):
                yield (name, value)
    
    def __len__(self): return len(list(self.attrs()))
    
    def copy(self):
        kw = {}
        for name, value in self.static():
            kw[name] = getattr(self, name)
            
        c = self.__class__(**kw)
        
        c._dynamic_attrs = self._dynamic_attrs
        c.name = self.name
        
        for name, value in self.static():
            setattr(c, name, getattr(self, name))
        
        for name, value in self._data.items():
            setattr(c, name, value)
        #c.data = copy.deepcopy(attr.data)
        
        assert c._data is not self._data
        
        
        return c
    
    @classmethod
    def class_attrs(self):
        for attr in self._attributes:
            yield attr
    
    def attrs(self):
        for attr in self._attributes:
            yield attr
        for attr in self._dynamic_attrs:
            yield attr
    
    def num_attrs(self): return len(list(self.attrs()))
    
    def static_attr(self, name):
        for attr in self._attributes:
            if attr.static and attr.name == name:
                return attr
    
    def dynamic_attr(self, name):
        for attr in self._dynamic_attrs:
            if attr.name == name:
                return attr
            
    def add_dynamic_attr(self, attr, value):
        self._dynamic_attrs.append(attr)
        self._set_data(attr, value)
        setattr(self, attr.name, value)
        
    def del_dynamic_attr(self, attr):
        self._dynamic_attrs.remove(attr)
        
    def __setattr__(self, name, value):
        attr_names = name.split('.')
        first_attr = attr_names[0]
        if len(attr_names) > 1:
            val = getattr(self, first_attr)
            setattr(val, '.'.join(attr_names[1:]), value)
            return
        
        attr = self.dynamic_attr(name)
        if attr is not None:
            attr.__set__(self, value)
        else:
            object.__setattr__(self, name, value)
        
    def __getattr__(self, name):
        attr_names = name.split('.')
        first_attr = attr_names[0]
        if len(attr_names) > 1:
            first_val = getattr(self, first_attr)
            return getattr(first_val, '.'.join(attr_names[1:]))
        attr = self.dynamic_attr(first_attr)
        if attr is None:
            raise AttributeError(str(self) + " has no attribute " + str(name))
        return attr.__get__(self, attr)
    
    @classmethod
    def add_class_attr(cls, attr):
        cls._attributes.append(attr)
        setattr(cls, attr.name, attr)
    
    def add_attr(self, attr, value=None):
        self._attributes.append(attr)
        setattr(self.__class__, attr.name, attr)
        setattr(self, attr.name, value)
    
    
    @classmethod
    def del_attr(self, attr):
        self._attributes.remove(attr)
        #del self._data[attr.name]
        
        # There must be a better way then this
        globals()[self.__name__] = self
        exec "del "+self.__name__ + "." + attr.name
        
    
    def attr_at(self, index):
        return itertools.islice(self.attrs(), index, index+1).next()
    
    def attr_named(self, name):
        for attr in self.attrs():
            if attr.name == name:
                return attr
            
    def __iter__(self): return DataIter(self)
    
    def __set__(self, instance, value):
        if isinstance(value, Expression):
            return instance._set_data(self, value)
            
        val_type_name = value.__class__.__name__
        data_obj = getattr(instance, self.name)
        if value is data_obj: 
            return
        

        
        convert_fn = 'from_'+val_type_name
        if hasattr(data_obj, convert_fn):
            getattr(data_obj, convert_fn)(value)
            #instance._set_data(self, self)
            return

        if type(value) == type(data_obj):
            instance._set_data(self, value)
            return
        
        raise ValueError("Dont know how to convert "+ str(value.__class__.__name__) + 
                         " to " + self.__class__.__name__ + " in attribute: " + str(instance.name) + "." + str(self.name))
    
    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        data = instance._get_data(self)
        if isinstance(data, Expression):
            return data.eval(instance)
        return data
    
    def __getitem__(self, key):
        if isinstance(key, int):
            attr = self.attr_at(key)
        elif isinstance(key, str):
            attr = self.attr_named(key)
        else:
            raise AttributeError("Key must be int or string")
        return self.get_data(attr)
    
    def __setitem__(self, key, value):
        if isinstance(key, int):
            attr = self.attr_at(key)
        elif isinstance(key, str):
            attr = self.attr_named(key)
        else:
            raise AttributeError("Key must be int or string")
        self.set_data(attr, value)

    def get_data(self, attr):
        return getattr(self, attr.name)
    def set_data(self, attr, value):
        setattr(self, attr.name, value)

    def _get_data(self, attr):
        if not self._data.has_key(attr.name):
            if attr in list(self.attrs()):
                setattr(self, attr.name, attr.default_value(self))
        return self._data[attr.name]
    
    def _set_data(self, attr, value):
        self._data[attr.name] = value
        if hasattr(self, 'change'):
            self.change(attr, value)
        
    def on_data_change(self):
        print 'DATA CHANGED'
        
    @classmethod
    def _get_static_data(cls, attr):
        getattr(cls, attr.name)
    
    
    def __call__(self, *args, **kw):
        ''' Calling an Component instance, will make a new Component with this as it's Proxy. '''
        return
        __register = kw.get('__register', True)
        sub_comp = self.__class__(__proxy=self, __register=__register)
        
        # Override the attributes with the names given in args
        for name in args:
            sub_comp.override(name, getattr(self, name))
            
        # Override the attributes with name and values given in kw
        for name, value in kw.items():
            if name.startswith("_"): continue
            sub_comp.override(name, value)
            
        return sub_comp
    
    def parent_components(self):
        ''' Get all components that links to this '''
        for name, value in self.__parent_links.iteritems():
            for parent in value:
                yield parent.parent.instance
    
    def parents_of_type(self, type_name):
        ''' Get the parent components which class is named 'type_name' '''
        return self.__parent_links.get(type_name, [])
    
    def _add_parent_link(self, link):
        ''' Add a parent link to this component '''
        link_parent_name = link.parent.instance.__class__.__name__
        if not hasattr(self.__parent_links, link_parent_name):
            self.__parent_links[link_parent_name] = []
        self.__parent_links[link_parent_name].append(link)
    
    def get_proxy(self): 
        return self.__proxy
    def set_proxy(self, c): 
        assert isinstance(c, ComponentBase)
        self.__proxy = c
    proxy = property(get_proxy, set_proxy)
    
    def get_parent(self):
        return self._parent
    
    def set_parent(self, parent):
        print 'SETTING PARENT', self, parent, list(self.parents()), self.parent
        
        if parent is not None and not isinstance(parent, ComponentBase):
            raise TypeError("parent must be a Component type")
        
        if parent is not None and parent.has_parent(self):
            raise ValueError('is already parent')
        
        if self._parent is not None:
            self._parent._children.remove(self)
        
        self._parent = parent
        if parent is not None:
            parent._children.append(self)
        ParentChanged(self)
        
    def parents(self):
        parent = self.parent
        while 1:
            if parent is None:
                break
            yield parent
            parent = parent.parent
        
    def has_parent(self, obj):
        for parent in self.parents():
            if isinstance(obj, str) and parent.name == obj:
                return True
            if isinstance(obj, (types.ClassType, type,)) and parent.__class__ is obj:
                return True
            if parent is obj:
                return True
        return False
        
    parent = property(get_parent, set_parent)
        
    def add_child(self, child):
        print 'ADD CHILD', child
        
        if not isinstance(child, ComponentBase):
            raise TypeError("children must be a Component type")
        
        if child in self._children:
            return
        
        self._children.append(child)
        child.parent = self
        
    
    def remove_child(self, child):
        if not child in self._children:
            return
        child.parent = None
    
    
    
    '''
    def __getstate__(self):
        # Called when pickling this object 
        data_dict = {}
        for name, value in self.data_handles():
            vdata = value._data
            if hasattr(vdata, '__iter__'):
                vdata = [item._data for item in vdata if isinstance(item, DataHandle)]
            data_dict[name] = vdata
            
        data_dict['__parent_links'] = self.__parent_links
        return data_dict
    
    def __setstate__(self, state):
        # Called when pickle loads this component 
        self.__init__(self)
        self.__parent_links = state.get('__parent_links')
        if self.__parent_links is None:
            self.__parent_links = {}
        else:
            del state['__parent_links']
        for name, value in state.items():
            self._set_data(name, value, signal=False)
    '''
    
    def note_change(self):
        print 'NOTE CHANGE', self
        self._data._p_note_change()
        self.change()
    
    def data_changed(self, data):
        ''' Called when any data on this component changes '''
        # Signal that some data has changed
        self.change()
    
    
    def get_attr(self, attr_name):
        ''' Get the attribute with the given name '''
        for attr in self.attrs():
            if attr.name == attr_name:
                return attr
    
    
    def set(self, **kw):
        ''' '''
        for name, value in kw.iteritems():
            setattr(self, name, value)
    
    def override(self, attr_name, value):
        ''' Override the proxy data with the given value '''
        if self.proxy is None:
            raise AttributeError(str(self) + " has no proxy object")
        
        self.add_handle(attr_name)
        setattr(self, attr_name, value)
    
    def sub_data(self): return self._data
    data_dict = sub_data
    
    def input_data(self):
        data = {}
        for attr in self.input_attrs():
            data[attr.name] = getattr(self, attr.name)
        return data

    def output_data(self):
        data = {}
        for attr in self.output_attrs():
            data[attr.name] = getattr(self, attr.name)
        return data
    
    def input_attrs(self):
        return filter(lambda attr: not attr.is_output(), self.attrs())
        
    def output_attrs(self):
        return filter(lambda attr: attr.is_output(), self.attrs())
            
    def is_output(self):
        return bool(self.depends)
         
    def get_compute_method(self, attr):
        ''' Get the method used to compute the value of the given attribute '''
        assert attr.is_output()
        name = "compute_" + str(attr.name)
        if not hasattr(self, name):
            raise TypeError(str(self) + " has no compute method for Attribute: " + str(attr))
        
        return getattr(self, name)
    
    def update_attr(self, attr):
        ''' Evaluate Attribute '''
        if not attr.is_output():
            raise TypeError("Attribute is not output: " + str(attr))
        compute_func = self.get_compute_method(attr)
        compute_result = compute_func()
        setattr(self, attr.name, compute_result)
    
    def prepare_update(self):
        pass
    
    def update(self):
        ''' Update all output attributes '''
        for attr in self.output_attrs():
            self.update_attr(attr)
        self.change()
    
    '''
    def _get_data(self, attr_name, proxy=None):
        ''' '''
        handler = self.get_handle(attr_name)
        if handler is None:
            self.add_handle(attr_name)
            handler = self.get_handle(attr_name)
            
        if not handler is None:
            return handler.get(proxy=proxy)
        elif not self.proxy is None:
            return self.proxy._get_data(attr_name, self)
        else:
            raise AttributeError(attr_name + " does not exists on " + str(self.__class__.__name__))
    
    def _set_data(self, attr_name, value, signal=True):
        ''' '''
        handler = self.get_handle(attr_name)
        if handler is not None:
            handler.set(value, signal)
        elif self.proxy is not None:
            self.proxy._set_data(attr_name, value, signal)
        else:
            raise AttributeError(attr_name + " does not exists on " + str(self.__class__.__name__))
    '''



class ServerComponent(ComponentBase):
    
    def __new__(cls, *args, **kw):
        raise Error("ServerComponent should new be instansiated")
        # My farvorit hack so far
        #if cls.plugin is not None:
        #    PluginManager().load_plugin(cls.plugin)
        
        # @todo: do something..
        #return cls.__bases__[0].__new__(cls, *args, **kw)
    
    

class ComponentStem(ComponentBase):
    plugin = None
    def __init__(self, *args, **kw):
        raise Error("This class should not be used anymore")
        self.kw = kw
        ComponentBase.__init__(self, *args, **kw)
        if self.plugin is not None:
            PluginManager().load_plugin(self.plugin)
    
    @classmethod
    def transform_into(cls, component_cls, instances):
        for attr in component_cls.class_attrs():
            cls.add_class_attr(attr)
        
        cls.__bases__ = component_cls.__bases__
        cls.__name__ = component_cls.__name__
        cls.dependencies = component_cls.dependencies
        
        for inst in instances:
            pass
            #inst.generate_data()
            #inst.set(**inst.kw)
        
        #print cmds.dbitems()
        
    def __str__(self): return "ComponentStem: " + str(self.__class__.__name__)
        
    def add_handle(self, attr_name):
        attr = self.get_attr(attr_name)
        if attr is None:
            attr = AttributeBase()
        self.__data_handlers[attr_name] = attr.create_handle(self)
    
class NamedComponent(object):
    def __init__(self, name, plugin):
        self.name = name
        self.plugin = plugin
        NewNamedComponent(self)



class CompoundData(ComponentBase):
    pass


class WidgetMeta(type):
    def __new__(self, name, bases, ns):
        cls = type.__new__(self, name, bases, ns)
        NewWidgetType(cls)
        return cls

class WidgetBase(object):
    __metaclass__ = WidgetMeta
    attribute = None

class Editor(WidgetBase):
    ''' '''
    widget = None
    display = None
    attribute = None
    
    def __init__(self, data, *args, **kw):
        self.data = data
        self.init_display()
        self.init_editor()
        
        self.setup()
        
    
    def init_display(self):
        display_cls = self.__class__.display
        if display_cls is None: return
        self.display = display_cls(None)
        
    def init_editor(self):
        editor_cls = self.__class__.widget
        if editor_cls is None: return
        self.widget = editor_cls(None)
        self.widget.setAutoFillBackground(True)
    
    def __str__(self): return "Editor "+str(self.__class__.__name__) + " for data " + str(self.data.name())
    
    def __del__(self): pass

    def __getstate__(self): return {}
    def __setstate__(self, state): pass